﻿using DotPowerJob.Models;
using DotPowerJob.Queue;
using DotPowerJob.Requests;
using DotPowerJob.Responses;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;

namespace DotPowerJob
{
    /// <summary>
    /// Job轮询
    /// </summary>
    public class JobDispatcher
    {
        private readonly ConcurrentDictionary<int, JobTaskQueue> RUNNING_QUEUE = new ConcurrentDictionary<int, JobTaskQueue>();
        private readonly ConcurrentDictionary<long, int> ID_IN_QUEUE = new ConcurrentDictionary<long, int>();

        private readonly ILogger _logger;
        private readonly ITaskExecutor _executor;
        private readonly PowerJobConfig _jobConfig;
        public JobDispatcher(ILogger<JobDispatcher> logger, ITaskExecutor taskExecutor, IOptions<PowerJobConfig> options)
        {
            this._logger = logger;
            this._executor = taskExecutor;
            if (options == null)
                throw new ArgumentNullException(nameof(options));
            this._jobConfig = options.Value;
        }

        public bool TryRemoveInstanceTask(long instanceeId)
        {
            if (ID_IN_QUEUE.TryRemove(instanceeId, out var jobId))
            {
                if (RUNNING_QUEUE.TryGetValue(jobId, out var jobQueue))
                {
                    jobQueue.StopInstance(instanceeId);
                    return true;
                }
            }
            return true;
        }

        public PowerJobResponse Execute(ServerScheduleJobRequest request)
        {
            if (RUNNING_QUEUE.TryGetValue(request.JobId, out var taskQueue))
            {
                if (taskQueue != null)
                {
                    if (taskQueue.IsRunning())
                    {
                        return PowerJobResponse.Failed($"有正在执行中的任务");
                    }
                }
            }
            return this.PushJobQueue(request);
        }

        private PowerJobResponse PushJobQueue(ServerScheduleJobRequest triggerParam)
        {

            if (RUNNING_QUEUE.TryGetValue(triggerParam.JobId, out var jobQueue))
            {
                ID_IN_QUEUE.TryAdd(triggerParam.InstanceId, triggerParam.JobId);
                return jobQueue.Push(triggerParam);
            }

            //NewJobId
            jobQueue = new JobTaskQueue(this._executor, this._logger, this._jobConfig);
            if (RUNNING_QUEUE.TryAdd(triggerParam.JobId, jobQueue))
            {
                ID_IN_QUEUE.TryAdd(triggerParam.InstanceId, triggerParam.JobId);
                return jobQueue.Push(triggerParam);
            }
            return PowerJobResponse.Failed("add running queue executor error");
        }
    }
}
